package com.game.framework.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 基本工具类
 *
 * @author ming27
 */
@Slf4j
public class CommUtil {
  private static final String DEFAULT_PATTERN_DAY_TIME = "yyMMddHHmmssSSS";

  private static final String GREEN_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";

  /** 一周的天数 */
  private static final int DAYS_OF_WEEK = 7;

  public static final long ONE_DAY = 86400000L;

  private CommUtil() {
    throw new AssertionError();
  }

  /**
   * 此函数是用来造假的，以后会废弃掉，索性里面写死一个hash，这样 一眼能看出来是造假的
   *
   * @param num 多少个
   * @return 数字字串列表
   */
  public static List<String> fetchNum(int num) {
    List<String> resList = new ArrayList<>(num);
    for (int i = 0; i < num; i++) {
      resList.add("077c12fc20cd306396837758a1c4c1039de71f6ae75aaebf1b253d32c85b3aaf");
    }
    return resList;
  }

  /**
   * 取得两位整数
   *
   * @param hashStr hash值
   * @return 数字
   */
  public static int calcFetchNum(String hashStr) {
    String numStr = hashStr.replaceAll("\\D", "");
    if (numStr.length() >= 2) {
      numStr = numStr.substring(numStr.length() - 2);
      return Integer.parseInt(numStr);
    } else {
      log.error("CommUtil.calcFetchNum() error! hashStr=" + hashStr);
      return -1;
    }
  }

  /**
   * 循环取数
   *
   * @param fetchTime 第几次取(从0开始)
   * @param lastNum 上一次的取的数
   * @param total 循环的基数(第一次取数的池子大小)
   * @param curRandomNum 当前随机的数
   * @return 本次该取的数
   */
  public static int cycleFetchNum(int fetchTime, int lastNum, int total, int curRandomNum) {
    return (lastNum + curRandomNum) % (total - fetchTime);
  }

  /**
   * 计算下注的总数
   *
   * @param list 下注列表
   * @return 下注的总和
   */
  public static long sumListLong(List<Long> list) {
    return list.stream().mapToLong(Long::longValue).sum();
  }

  public static String trimBlockHash(String blockHash) {
    if (blockHash.length() != 64) {
      return "";
    }
    String temp = blockHash.substring(10).replaceAll("\\D", "");
    if (temp.length() % 2 != 0) {
      temp = temp.substring(1);
    }
    return temp;
  }

  public static List<String> fetchNumList(String trimHash, int max) {

    if (trimHash.length() < 2) {
      return null;
    }
    List<String> result = new ArrayList<>();
    int len = trimHash.length();
    int total = len / 2;
    int times = Math.min(total, max);
    String tmp;
    for (int i = 0; i < times; i++) {
      int begin = len - i * 2 - 2;
      int end = begin + 2;
      tmp = trimHash.substring(begin, end);
      result.add(tmp);
    }
    return result;
  }

  /**
   * 获取字符串真实的类型
   *
   * @param value 字符串
   * @return Class
   */
  public static Class<?> getTypeFromString(String value) {
    // 忽略所有空字符串或全是空格的字符串
    if (StringUtils.isBlank(value)) {
      return String.class;
    }
    if (StringUtils.isNumeric(value)) {
      if (Long.parseLong(value) > Integer.MAX_VALUE) {
        return Long.class;
      }
      return Integer.class;
    }
    if (value.equalsIgnoreCase(Boolean.TRUE.toString())
            ||value.equalsIgnoreCase(Boolean.FALSE.toString())) {
      return Boolean.class;
    }
    try {
      Double.parseDouble(value);
      return Double.class;
    } catch (Exception ignore) {
    }
    return String.class;
  }

  /**
   * 判断两个毫秒类型是否同一天
   *
   * @param one 毫秒
   * @param two 毫秒
   * @return boolean
   */
  public static boolean isSameDay(long one, long two) {
    Calendar c1 = Calendar.getInstance();
    c1.setTimeInMillis(one);
    Calendar c2 = Calendar.getInstance();
    c2.setTimeInMillis(two);
    return ((c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR))
            && (c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR)));
  }

  /**
   * 当前时间的 格式化
   *
   * @return String
   */
  public static String parseTodayNow() {
    SimpleDateFormat nowDate = new SimpleDateFormat(DEFAULT_PATTERN_DAY_TIME);
    StringBuffer sb = new StringBuffer();
    nowDate.format(new Date(), sb, new FieldPosition(10));
    return sb.toString();
  }

  /**
   * 给指定日期增加days天，并返回被更改的日期对象
   *
   * @param days int
   * @return Calendar
   */
  public static Date addDays(int days) {
    Calendar basic = Calendar.getInstance();
    basic.add(Calendar.DAY_OF_MONTH, days);
    return basic.getTime();
  }

  /**
   * 给指定日期增加second，并返回被更改的日期对象
   *
   * @param second int
   * @return Calendar
   */
  public static Date addSecond(int second) {
    Calendar basic = Calendar.getInstance();
    basic.add(Calendar.SECOND, second);
    return basic.getTime();
  }

  /**
   * 获得某天最小时间
   *
   * @param date Date
   * @return Date
   */
  public static Date getStartOfDay(Date date) {
    LocalDateTime localDateTime =
            LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
    LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
    return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
  }

  /**
   * 判断输入时间是否已经过去了24小时
   *
   * @param dateTime Long
   * @return boolean
   */
  public static boolean passedOneDay(Long dateTime) {
    if (System.currentTimeMillis() < dateTime) {
      return false;
    }
    return System.currentTimeMillis() - dateTime > ONE_DAY;
  }

  /**
   * 判断输入时间是否已经过去了24小时
   *
   * @param dateTime Long
   * @return int
   */
  public static int passedDays(Long dateTime) {
    if (System.currentTimeMillis() < dateTime) {
      return 0;
    }
    long passedTimes = System.currentTimeMillis() - dateTime;
    return (int) (passedTimes / ONE_DAY);
  }

  /**
   * 获取本周开始时间的时间戳
   *
   * @param time Long
   * @return long
   */
  public static long getBeginOfWeek(long time) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(time);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.DAY_OF_WEEK, 1);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTimeInMillis();
  }

  /**
   * 判断start和end是否在同一个星期内(周一为一周开始)
   *
   * @param start long
   * @param end long
   * @return boolean
   */
  public static boolean isInSameWeek(long start, long end) {
    Calendar st = Calendar.getInstance();
    st.setTimeInMillis(start);
    Calendar et = Calendar.getInstance();
    et.setTimeInMillis(end);
    int days = Math.abs(getSoFarWentDays(st, et));
    if (days < DAYS_OF_WEEK) {
      // 设置Monday为一周的开始
      st.setFirstDayOfWeek(Calendar.MONDAY);
      et.setFirstDayOfWeek(Calendar.MONDAY);
      return st.get(Calendar.WEEK_OF_YEAR) == et.get(Calendar.WEEK_OF_YEAR);
    }
    return false;
  }

  /**
   * 以日期中的日为实际计算单位，计算两个时间点实际日的差距 比如 12-1 23:00 和12-2 01:00，相差1天，而不是小于24小时就算做0天 如果(now -
   * st)为正，则表示now在st之后
   *
   * @param st Calendar
   * @param now Calendar
   * @return int
   */
  public static int getSoFarWentDays(Calendar st, Calendar now) {
    int sign = st.before(now) ? 1 : -1;
    if (now.before(st)) {
      Calendar tmp = now;
      now = st;
      st = tmp;
    }
    int days = now.get(Calendar.DAY_OF_YEAR) - st.get(Calendar.DAY_OF_YEAR);
    if (st.get(Calendar.YEAR) != now.get(Calendar.YEAR)) {
      Calendar cloneSt = (Calendar) st.clone();
      while (cloneSt.get(Calendar.YEAR) != now.get(Calendar.YEAR)) {
        days += cloneSt.getActualMaximum(Calendar.DAY_OF_YEAR);
        cloneSt.add(Calendar.YEAR, 1);
      }
    }
    return days * sign;
  }

  /**
   * 当前时间的 格式化
   *
   * @return String
   */
  public static String getGreenDateTimeFormat() {
    Date date = new Date();
    SimpleDateFormat dateFormat = new SimpleDateFormat(GREEN_PATTERN);
    return dateFormat.format(date);
  }
}
